package be.rubengerits.test;

import android.util.*;
import java.lang.reflect.*;

public class JsonFactory {

	private static final String PACKAGENAME = "be.rubengerits.test.objects";

	private JsonFactory() {
	}

	private static JsonObject getInstance(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		Class<?> c = Class.forName(PACKAGENAME + "." + className);
		return (JsonObject) c.newInstance();
	}

	private static JsonObject getInstance(Class<?> objectClass) throws InstantiationException, IllegalAccessException {
		return (JsonObject) objectClass.newInstance();
	}

	public static JsonObject parseObject(String jsonName, JsonReader reader, Class<?> objectClass, JsonObject parent) throws Exception {
		JsonObject object = getInstance(objectClass)/*constructObject(jsonName)*/;
		object.setName(jsonName);
		object.setParent(parent);

		boolean running = true;
		while (running) {
			running = handleNext(reader, object);
		}

		return object;
	}

	private static JsonObject constructObject(String jsonName) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		String name = JsonUtils.constructName(jsonName);
		JsonObject object = getInstance(name);
		object.setName(name);
		return object;
	}

	private static boolean handleNext(JsonReader reader, JsonObject object) throws Exception {
		JsonToken nextType = reader.peek();

		String childName = "";
		boolean isArray = false;
		if (JsonToken.BEGIN_OBJECT == nextType) {
			reader.beginObject();
			Log.v("progress", "begin object");
		} else if (JsonToken.BEGIN_ARRAY == nextType) {
			reader.beginArray();
			reader.beginObject();
			isArray = true;
			Log.v("progress", "begin array");
		}

		childName = reader.nextName();
		nextType = reader.peek();
		if (JsonToken.BEGIN_ARRAY == nextType || isArray) {
			JsonArray array = new JsonArray();
			array.setName(JsonUtils.constructName(childName));
			array.setParent(object);
			Log.v("-- step", "array");
			object.setValue(JsonUtils.constructName(childName), array);
		} else if (JsonToken.STRING == nextType) {
			JsonString string = new JsonString();
			string.setValue(reader.nextString());
			object.setValue(JsonUtils.constructName(childName), string);
			Log.v("-- step", "string");
		} else if (JsonToken.NUMBER == nextType) {
			JsonNumber number = new JsonNumber();
			number.setValue(reader.nextDouble());
			object.setValue(JsonUtils.constructName(childName), number);
			Log.v("-- step", "number");
		} else if (JsonToken.BEGIN_OBJECT == nextType) {
			Class<?> c = getChildClass(object, childName);
			JsonObject child = parseObject(childName, reader, c, object);
			object.setValue(child.getName(), child);
			Log.v("-- step", "object");
		}

		if (JsonToken.END_OBJECT == reader.peek()) {
			reader.endObject();
			Log.v("progress", "end objecy");
			return false;
		} else if (JsonToken.END_ARRAY == nextType) {
			reader.endArray();
			Log.v("progress", "end array");
			return false;
		}

		return true;
	}

	public static Class<?> getChildClass(JsonObject object, String childName) throws Exception {
		Class<?> thisClass = object.getClass();
		//Log.v("testapp-1", object.getName() +"-"+ object.getClass().getName());
		
		if (object instanceof JsonArray) {
			Class<?> parentClass = object.getParent().getClass();
			ParameterizedType t = (ParameterizedType) parentClass.getDeclaredField(object.getName()).getGenericType();
			thisClass = (Class<?>) t.getActualTypeArguments()[0];
		}
		//Log.v("testapp-2", thisClass.getName());
		
		Field f = thisClass.getDeclaredField(JsonUtils.constructFieldName(childName));
		//Log.v("testapp-3", f.getClass().getName());
		
		return f.getType();
	}

}
